﻿//-----------------------------------------------------------------------
// <copyright file="CustomizedPagination.ascx.cs" company="CMSN Software">
//    Copyright © 2011  CMSN Software
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see http://www.gnu.org/licenses.
// </copyright>
//-----------------------------------------------------------------------

namespace CMSN.Software.Tutorials.HowToUseCustomPagination
{
    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Globalization;
    using System.Web;
    using System.Web.UI.WebControls;

    /// <summary>
    /// Enumeration for pagination mode
    /// </summary>
    public enum PaginationType
    {
        /// <summary>
        /// range mode
        /// </summary>
        Range,

        /// <summary>
        /// numeric mode
        /// </summary>
        Numeric
    }

    /// <summary>
    /// pagination control for repeater
    /// </summary>
    public partial class CustomizedPagination : System.Web.UI.UserControl
    {
        /// <summary>
        /// configuration name of search result page url
        /// </summary>
        private const string MobileJobSearchResultPageConfigName = "MobileJobSearchResultPage";

        /// <summary>
        /// NameValueCollection for get or set query string
        /// </summary>
        private NameValueCollection queryString;

        #region Public Properties
        /// <summary>
        /// Gets or sets the pagination mode.
        /// </summary>
        /// <value>
        /// The pagination mode.
        /// </value>
        [DefaultValue(PaginationType.Range)]
        public PaginationType PaginationMode { get; set; }

        /// <summary>
        /// Gets or sets the size of the pagination.
        /// </summary>
        /// <value>
        /// The size of the pagination.
        /// </value>
        public int PaginationSize { get; set; }

        /// <summary>
        /// Gets or sets the repeater control.
        /// </summary>
        /// <value>
        /// The repeater control.
        /// </value>
        public Repeater RepeaterControl { get; set; }

        /// <summary>
        /// Gets or sets the data source.
        /// </summary>
        /// <value>
        /// The data source.
        /// </value>
        public IEnumerable DataSource { get; set; }

        /// <summary>
        /// Gets or sets the total record count.
        /// </summary>
        /// <value>
        /// The total record count.
        /// </value>
        public int TotalRecordCount { get; set; }

        /// <summary>
        /// Gets the current page.
        /// </summary>
        public int CurrentPage
        {
            get
            {
                int pageNumber = 1;
                if (!string.IsNullOrEmpty(Request["CurrentPage"]))
                {
                    pageNumber = int.Parse(Request["CurrentPage"], CultureInfo.CurrentCulture);
                }

                return pageNumber;
            }
        }

        /// <summary>
        /// Gets the page count.
        /// </summary>
        public int PageCount
        {
            get
            {
                return ViewState["_PageCount"] == null ? 0 : int.Parse(ViewState["_PageCount"].ToString(), CultureInfo.InvariantCulture);
            }

            private set
            {
                ViewState["_PageCount"] = value;
            }
        }

        /// <summary>
        /// Gets the Results count.
        /// </summary>
        public int Count
        {
            get
            {
                return ViewState["_Count"] == null ? 0 : int.Parse(ViewState["_Count"].ToString(), CultureInfo.InvariantCulture);
            }

            private set
            {
                ViewState["_Count"] = value;
            }
        }

        /// <summary>
        /// Gets the current page text.
        /// </summary>
        public string CurrentPageText
        {
            get
            {
                return ViewState["_CurrentPageText"] == null ? "0" : ViewState["_CurrentPageText"].ToString();
            }

            private set
            {
                this.ViewState["_CurrentPageText"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the pagination point CSS class.
        /// </summary>
        /// <value>
        /// The pagination point CSS class.
        /// </value>
        public string PaginationPointCssClass { get; set; }

        /// <summary>
        /// Gets or sets the seected page CSS class.
        /// </summary>
        /// <value>
        /// The seected page CSS class.
        /// </value>
        public string SelectedPageCssClass { get; set; }

        /// <summary>
        /// Gets or sets the CSS class.
        /// </summary>
        /// <value>
        /// CSS class for the paginatiopn control
        /// </value>
        public string CssClass { get; set; }

        /// <summary>
        /// Gets or sets the navigation CSS class.
        /// </summary>
        /// <value>
        /// The navigation CSS class.
        /// </value>
        public string NavigationCssClass { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether [show first last].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [show first last]; otherwise, <c>false</c>.
        /// </value>
        [DefaultValue(false)]
        public bool ShowFirstLast { get; set; }

        /// <summary>
        /// Gets or sets the first page link text.
        /// </summary>
        /// <value>
        /// The first page link text.
        /// </value>
        [DefaultValue("<<")]
        public string FirstPageLinkText { get; set; }

        /// <summary>
        /// Gets or sets the last page link text.
        /// </summary>
        /// <value>
        /// The last page link text.
        /// </value>
        [DefaultValue(">>")]
        public string LastPageLinkText { get; set; }

        /// <summary>
        /// Gets or sets the previous page link text.
        /// </summary>
        /// <value>
        /// The previous page link text.
        /// </value>
        [DefaultValue("<")]
        public string PreviousPageLinkText { get; set; }

        /// <summary>
        /// Gets or sets the next page link text.
        /// </summary>
        /// <value>
        /// The next page link text.
        /// </value>
        [DefaultValue(">")]
        public string NextPageLinkText { get; set; }
        #endregion

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            this.queryString = HttpUtility.ParseQueryString(Request.QueryString.ToString());
            this.GeneratePagination();
            this.FirstPageLink.NavigateUrl = this.GenerateNavigationLink(1);
            this.LastPageLink.NavigateUrl = this.GenerateNavigationLink(this.PageCount);
            this.PreviousPageLink.NavigateUrl = this.GenerateNavigationLink(this.CurrentPage - 1);
            this.NextPageLink.NavigateUrl = this.GenerateNavigationLink(this.CurrentPage + 1);
            if (this.ShowFirstLast)
            {
                // hide first page link on first page.
                this.PreviousPageLink.Visible = this.FirstPageLink.Visible = !(this.CurrentPage == 1);

                // hide last page link on last page.
                this.NextPageLink.Visible = this.LastPageLink.Visible = !(this.CurrentPage == this.PageCount);

                // set the first page link text
                if (!string.IsNullOrEmpty(this.FirstPageLinkText))
                {
                    this.FirstPageLink.Text = this.FirstPageLinkText;
                }

                // set the last page link text
                if (!string.IsNullOrEmpty(this.LastPageLinkText))
                {
                    this.LastPageLink.Text = this.LastPageLinkText;
                }

                if (!string.IsNullOrEmpty(this.PreviousPageLinkText))
                {
                    this.PreviousPageLink.Text = this.PreviousPageLinkText;
                }

                if (!string.IsNullOrEmpty(this.NextPageLinkText))
                {
                    this.NextPageLink.Text = this.NextPageLinkText;
                }
            }
            else
            {
                this.FirstPageLink.Visible = false;
                this.LastPageLink.Visible = false;
            }

            this.NextPageLink.CssClass = this.PreviousPageLink.CssClass = this.FirstPageLink.CssClass = this.LastPageLink.CssClass = this.NavigationCssClass;
            this.Pagination.CssClass = this.CssClass;
        }

        /// <summary>
        /// Creates the pagination point.
        /// </summary>
        /// <param name="title">title of the pagination point</param>
        /// <param name="index">index of the pagination point</param>
        /// <returns>Pagination point link</returns>
        private HyperLink CreatePaginationPoint(string title, int index)
        {
            HyperLink paginationPoint = new HyperLink();
            paginationPoint.ID = index.ToString(CultureInfo.InvariantCulture);
            paginationPoint.Text = title;
            paginationPoint.CssClass = this.PaginationPointCssClass;
            paginationPoint.NavigateUrl = this.GenerateNavigationLink(index + 1);
            return paginationPoint;
        }

        /// <summary>
        /// Generates the pagination.
        /// </summary>
        private void GeneratePagination()
        {
            PagedDataSource pagedDatasource = new PagedDataSource();
            pagedDatasource.DataSource = this.DataSource;
            pagedDatasource.AllowCustomPaging = true;
            pagedDatasource.AllowPaging = true;
            pagedDatasource.PageSize = this.PaginationSize;
            this.Count = this.TotalRecordCount;
            this.PaginationSize = (this.PaginationSize == 0) ? this.TotalRecordCount : this.PaginationSize;
            PaginationPoints.Controls.Clear();

            int startIndex = 0;
            if (this.TotalRecordCount % this.PaginationSize == 0)
            {
                this.PageCount = this.TotalRecordCount / this.PaginationSize;
            }
            else
            {
                this.PageCount = (this.TotalRecordCount / this.PaginationSize) + 1;
            }

            string paginationPointText;
            int startNumber;
            int endNumber;
            for (int i = startIndex; i < this.PageCount; i++)
            {
                startNumber = ((i + 1) * this.PaginationSize) + 1 - this.PaginationSize;
                endNumber = (i + 1) * this.PaginationSize > this.TotalRecordCount ? this.TotalRecordCount : (i + 1) * this.PaginationSize;
                if (this.PaginationMode == PaginationType.Numeric)
                {
                    paginationPointText = (i + 1).ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    paginationPointText = startNumber + " - " + endNumber;
                }

                if (i == this.CurrentPage - 1)
                {
                    this.CurrentPageText = paginationPointText;
                    using (Label selectedPage = new Label())
                    {
                        selectedPage.Text = paginationPointText;
                        selectedPage.CssClass = this.SelectedPageCssClass;
                        PaginationPoints.Controls.Add(selectedPage);
                    }
                }
                else if (i < this.PageCount)
                {
                    PaginationPoints.Controls.Add(this.CreatePaginationPoint(paginationPointText, i));
                }
            }

            this.RepeaterControl.DataSource = pagedDatasource;
            this.RepeaterControl.DataBind();
        }

        /// <summary>
        /// Generates the navigation link.
        /// </summary>
        /// <param name="linkIndex">Index of the link.</param>
        /// <returns>generated navigation link as a string</returns>
        private string GenerateNavigationLink(int linkIndex)
        {
            NameValueCollection linkUrl = this.queryString;
            linkUrl["CurrentPage"] = linkIndex.ToString(CultureInfo.InvariantCulture);
            string resultPage = Request.Url.GetLeftPart(UriPartial.Path);
            return resultPage + "?" + linkUrl.ToString();
        }
    }
}